using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using Microsoft.Xna.Framework.Content.Pipeline;

namespace XnaDevRu.ContentBuilder.Framework
{
	/// <summary>
	/// Represents content pipeline assembly class holding assemblies and their importers with processors.
	/// </summary>
    public class PipelineAssemblyManager
    {
        private static List<string> _assemblies = new List<string>();
        private static List<string> _processors = new List<string>();
        private static List<string> _importers = new List<string>();

        private static List<string> _processorNames = new List<string>();
        private static List<ContentImporterAttribute> _importerAttributes = new List<ContentImporterAttribute>();

        public static void ClearAll()
        {
            _assemblies.Clear();
            _processors.Clear();
            _importers.Clear();

            _processorNames.Clear();
            _importerAttributes.Clear();
        }

		/// <summary>
		/// Gets available content pipelines' array.
		/// </summary>
        public string[] Assemblies { get { return _assemblies.ToArray(); } }
		/// <summary>
		/// Gets available content processors' array.
		/// </summary>
        public string[] Processors { get { return _processors.ToArray(); } }
		/// <summary>
		/// Gets available content importers' array.
		/// </summary>
        public string[] Importers { get { return _importers.ToArray(); } }
		/// <summary>
		/// Gets available content processors' names array.
		/// </summary>
        public string[] ProcessorNames { get { return _processorNames.ToArray(); } }
		/// <summary>
		/// Gets available content importer attributes array.
		/// </summary>
        public ContentImporterAttribute[] ImporterAttributes { get { return _importerAttributes.ToArray(); } }

		/// <summary>
		/// Gets available content processors' collection.
		/// </summary>
        internal static List<string> ProcessorsCollection { get { return _processors; } }
		/// <summary>
		/// Gets available content processors' names collection.
		/// </summary>
        internal static List<string> ProcessorNameCollection { get { return _processorNames; } }
		/// <summary>
		/// Gets available content importers' collection.
		/// </summary>
        internal static List<string> ImporterCollection { get { return _importers; } }
		/// <summary>
		/// Gets available content importer attributes collection.
		/// </summary>
        internal static List<ContentImporterAttribute> ImporterAttributeCollection { get { return _importerAttributes; } }
		/// <summary>
		/// Gets available content pipelines' collection.
		/// </summary>
        internal static List<string> AssembliesCollection { get { return _assemblies; } }

		/// <summary>
		/// Adds new content pipeline assembly.
		/// </summary>
		/// <param name="fileName">Assembly filename.</param>
        public void AddAssembly(string fileName)
        {
			if (_assemblies.Contains(fileName))
				return;

            Assembly a = Assembly.LoadFile(fileName);
            _assemblies.Add(fileName);

            foreach (Type t in a.GetExportedTypes())
            {
                if (t.IsPublic && !t.IsAbstract)
                {
                    if (t.GetInterface(@"IContentImporter") != null)
                    {
                        object[] attributes = t.GetCustomAttributes(typeof(ContentImporterAttribute), false);
                        if (attributes != null && attributes.Length != 0)
                        {
                            ContentImporterAttribute importerAttribute = attributes[0] as ContentImporterAttribute;
                            _importerAttributes.Add(importerAttribute);
                        }
                        else
                        {
                            // If no attribute specify default one
                            ContentImporterAttribute importerAttribute = new ContentImporterAttribute(".*");
                            importerAttribute.DefaultProcessor = "";
                            importerAttribute.DisplayName = t.Name;
                            _importerAttributes.Add(importerAttribute);
                        }

                        _importers.Add(t.Name);
                    }
                    else if (t.GetInterface(@"IContentProcessor") != null)
                    {
                        object[] attributes = t.GetCustomAttributes(typeof(ContentProcessorAttribute), false);
                        if (attributes != null && attributes.Length != 0)
                        {
                            ContentProcessorAttribute processorAttribute = attributes[0] as ContentProcessorAttribute;
                            if (processorAttribute.DisplayName != null)
                            {
                                _processorNames.Add(processorAttribute.DisplayName);
                            }
                            else
                            {
                                _processorNames.Add(t.Name);
                            }
                        }
                        else
                        {
                            // If no attribute specify default name
                            _processorNames.Add(t.Name);
                        }

                        _processors.Add(t.Name);
                    }
                }
            }
        }

		/// <summary>
		/// Removes content pipeline.
		/// </summary>
		/// <param name="fileName">Assembly filename.</param>
        public void RemoveAssembly(string fileName)
        {
            if (_assemblies.Contains(fileName))
            {
                _assemblies.Remove(fileName);
                Assembly a = Assembly.LoadFile(fileName);

                foreach (Type t in a.GetExportedTypes())
                {
                    if (t.IsPublic && !t.IsAbstract)
                    {
                        if (t.GetInterface(@"IContentImporter") != null)
                        {
                            int index = _importers.IndexOf(t.Name);
                            _importerAttributes.RemoveAt(index);
                            _importers.Remove(t.Name);
                        }
                        else if (t.GetInterface(@"IContentProcessor") != null)
                        {
                            int index = _processors.IndexOf(t.Name);
                            _processorNames.RemoveAt(index); // Just remove processor name too...
                            _processors.Remove(t.Name);
                        }
                    }
                }
            }
        }

		/// <summary>
		/// Checks if the assembly is from XNA Framework.
		/// </summary>
		/// <param name="name">Assembly name.</param>
		/// <returns>True if assembly is from XNA Framework, false otherwise.</returns>
		public static bool IsDefaultAssembly(string name)
		{
			if (name.Contains(@"Microsoft.Xna.Framework.Content.Pipeline.EffectImporter.dll") ||
				name.Contains(@"Microsoft.Xna.Framework.Content.Pipeline.FBXImporter.dll") ||
				name.Contains(@"Microsoft.Xna.Framework.Content.Pipeline.TextureImporter.dll") ||
				name.Contains(@"Microsoft.Xna.Framework.Content.Pipeline.XImporter.dll"))
				return true;
			return false;
		}
    }
}
